package com.hzit.thread;

import org.junit.Test;

import java.util.concurrent.*;
import java.util.function.*;

/**
 * 类名：
 * 作者：WF
 * 功能：
 */
public class ThreadPoolDemo {
	public static void main(String[] args) throws ExecutionException, InterruptedException, TimeoutException {
		//1. 通过线程池创建
		//1.1 创建线程池的第一种方式:
		ExecutorService executorService = Executors.newFixedThreadPool(10);
		//1.2 创建线程池的第二种方式:
		ThreadPoolExecutor executor = new ThreadPoolExecutor(10, 20, 30,
				TimeUnit.SECONDS, new LinkedBlockingQueue<>(10000),
				Executors.defaultThreadFactory(),
				new ThreadPoolExecutor.AbortPolicy());
		//1.3 测试线程池的异步编排:
		//1.3.1 不会有输入也不会有输出,实现了Runnable接口
		// CompletableFuture.runAsync(() -> {
		// 	System.out.println("当前线程:" + Thread.currentThread().getName());
		// },executor);

		//1.3.2 实现了Supplier接口
		CompletableFuture<Integer> supplyAsync = CompletableFuture.supplyAsync(new Supplier<Integer>() {
			@Override
			public Integer get() {
				System.out.println("执行完成----1");
				return 10 / 2;
			}
		},executor);
		// Integer supplyResult = supplyAsync.get();       // 查看返回结果
		// System.out.println("supplyResult = " + supplyResult);

		//1.3.3 当上一个任务完成后,接着执行,
		// supplyAsync.whenComplete(new BiConsumer<Integer, Throwable>() {
		// 	@Override
		// 	public void accept(Integer rs, Throwable e) {       // rs: 上次输出的结果 e: 代表上次执行时的异常对象
		// 		System.out.println("rs = " + rs);
		// 		// 如果 上一次没有异常就不执行下面两行
		// 		String message = e.getMessage();
		// 		System.out.println(message);
		// 	}
		// });

		//1.3.4 当上一个任务有异常时,可以查看并处理异常,同时返回一个值
		// CompletableFuture<Integer> exceptionally = supplyAsync.exceptionally(new Function<Throwable, Integer>() {
		// 	@Override
		// 	public Integer apply(Throwable e) {
		// 		System.out.println("e = " + e);
		// 		try {
		// 			Thread.sleep(20000);
		// 			return 1;
		// 		} catch (InterruptedException interruptedException) {
		// 			interruptedException.printStackTrace();
		// 		}finally {
		// 			return 10;
		// 		}
		//
		// 	}
		// });
		// Integer exceptionVal = exceptionally.get(3,TimeUnit.SECONDS);
		// System.out.println("exceptionVal = " + exceptionVal);


		//1.4 handler方法处理
		//1.4.1 异步执行一下任务
		// CompletableFuture<Long> handleAsync = supplyAsync.handleAsync(new BiFunction<Integer, Throwable, Long>() {    // 参数1：上次返回结果 参数2：上次抛出的异常 参数3：向下返回的结果
		// 	@Override
		// 	public Long apply(Integer n, Throwable e) {
		// 		System.out.println("n = " + n);
		// 		System.out.println("e = " + e);
		// 		return 100L;
		// 	}
		// }, executor);
		// Long handleAsyncVal = handleAsync.get();
		// System.out.println("handleAsyncVal = " + handleAsyncVal);

		//1.5 串行化方法
		//1.5.1 实现了Runnable接口，无任何输入或输出参数
		// supplyAsync.thenRunAsync(()->{
		// 	System.out.println("实现了Runnable接口");
		// });
		//1.5.2 有输入参数，实现了Consumer接口
		// supplyAsync.thenAcceptAsync(new Consumer<Integer>() {
		// 	@Override
		// 	public void accept(Integer i) {
		// 		System.out.println("上次任务的结果是： " + i);
		// 	}
		// }, executor);

		//1.5.3 有输入参数及输出参数，实现了Function接口
		// CompletableFuture<Integer> applyAsync = supplyAsync.thenApplyAsync(new Function<Integer, Integer>() {  // 泛型1：输入参数 泛型2：输出参数
		// 	@Override
		// 	public Integer apply(Integer a) {
		// 		return a + 10;
		// 	}
		// });
		// Integer applyAsyncV = applyAsync.get();
		// System.out.println("applyAsyncV = " + applyAsyncV);


		//1.6 组合两个任务：(两个任务都要完成)
		//1.6.1 使用compine进行组合，有返回值
		//第一步：定义一个新任务
		CompletableFuture<Integer> supplyAsync1 = CompletableFuture.supplyAsync(new Supplier<Integer>() {
			@Override
			public Integer get() {
				try {
					Thread.sleep(10000);
					System.out.println("执行完成----2");
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
				return 4;
			}
		},executor);
		//第二步：组合两个任务
		// CompletableFuture<Integer> combineAsync1 = supplyAsync.thenCombineAsync(supplyAsync1, new BiFunction<Integer, Integer, Integer>() {
		// 	@Override
		// 	public Integer apply(Integer a, Integer b) {
		// 		return a + b;
		// 	}
		// },executor);
		// Integer combineAsyncV = combineAsync1.get();
		// System.out.println("combineAsyncV = " + combineAsyncV);

		//1.6.2 使用both组合,没有返回值
		// supplyAsync.thenAcceptBothAsync(combineAsync1, new BiConsumer<Integer, Integer>() {
		// 	@Override
		// 	public void accept(Integer a, Integer b) {
		// 		System.out.println("这两个任务组合后的结果相加：" + (a + b));
		// 	}
		// },executor);

		//1.6.3 当前面任务完成后，再执行本任务的业务逻辑
		// supplyAsync.runAfterBothAsync(combineAsync1, new Runnable() {
		// 	@Override
		// 	public void run() {
		// 		System.out.println("前面两个任务执行完成，现在轮到我了！");
		// 	}
		// });

		//1.7 组合两个任务：(两个任务只要有一个完成都可以)
		//1.7.1 只会得到上两个任务中有一个完成的值,不会返回值
		// supplyAsync.acceptEither(supplyAsync1, new Consumer<Integer>() {
		// 	@Override
		// 	public void accept(Integer a) {
		// 		System.out.println("a = " + a);
		// 	}
		// });
		//1.7.2 有输入参数和输出参数,两个参数中有一个完成任务的作为这里的输入参数
		// CompletableFuture<Long> applyToEitherAsync = supplyAsync.applyToEitherAsync(supplyAsync1, new Function<Integer, Long>() {  // 泛型1:输入参数 泛型2:输出参数
		// 	@Override
		// 	public Long apply(Integer a) {
		// 		return (long) (a + 10);
		// 	}
		// });
		// System.out.println("applyToEitherAsync.get() = " + applyToEitherAsync.get());

		// supplyAsync.runAfterEitherAsync(supplyAsync1, new Runnable() {
		// 	@Override
		// 	public void run() {
		// 		System.out.println("前两个任务有一个完成了,就轮到我了!");
		// 	}
		// },executor);

		//1.8 多任务组合:
		//1.8.1 所有任务完成
		CompletableFuture<Void> completableFuture = CompletableFuture.allOf(supplyAsync, supplyAsync1);
		completableFuture.get();
		//1.8.2 有一个任备就可以认为执行结束
		// CompletableFuture<Object> completableFuture = CompletableFuture.anyOf(supplyAsync, supplyAsync1);
		// completableFuture.get();
		System.out.println("hello ...");

	}

	// 1. 创建多线程的一种方式
	@Test
	public void test01() throws ExecutionException, InterruptedException {
		FutureTask<Long> ft = new FutureTask<>(new Callable<Long>() {
			@Override
			public Long call() throws Exception {
				return 10L;
			}
		});

		Thread thread = new Thread(ft);
		thread.start();
		Long t = ft.get();
		System.out.println("t = " + t);
	}
}
